﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using YetAnotherChat.ChatCore.Interfaces;
using YetAnotherChat.ChatCore.Models;
using YetAnotherChat.MemoryStorage.Interfaces;

namespace YetAnotherChat.ChatUI.Classes
{
    public class ChatMessagePersistenceService: IChatMessagePersistenceService
    {
        private IMessageRepository _messageRepo;

        private IMemoryQueueStorage _messageQueue;

        private const int _messageBatchCount = 500;//can be alot
        public CancellationTokenSource CancelToken = new CancellationTokenSource();
        private Thread _savingThread;
        private bool _running = false;
        private object _lock = new object();

        public ChatMessagePersistenceService(IMessageRepository messageRepo, IMemoryQueueStorage messageQueue)
        {
            _messageRepo = messageRepo;
            _messageQueue = messageQueue;
        }

        ~ChatMessagePersistenceService()
        {
            if (_savingThread != null && _savingThread.IsAlive)
                _savingThread.Abort();
        }

        public bool IsRunning
        {
            get
            {
                return _running;
            }
        }
      
        public event EventHandler Started;
        public event EventHandler Stopped;

        public void Stop()
        {
            if (_running)
            {
                lock (_lock)
                {
                    if (_running)
                    {
                        //trying to stop the current running background thread
                        if (_savingThread != null && _savingThread.IsAlive)
                        {
                            CancelToken.Cancel();
                            while (_savingThread.IsAlive)
                            {
                                //wait
                                Thread.Sleep(10);
                            }
                        }
                        _running = false;
                        if (Stopped != null)
                            Stopped(this, EventArgs.Empty);
                    }
                }
            }
        }

        public void Start()
        {
            if (!_running)
            {
                lock (_lock)
                {
                    if (!_running)
                    {
                        //starting a new thread
                        if (_savingThread == null || !_savingThread.IsAlive)
                        {
                            _savingThread = new Thread(SavingThreadStart);
                            CancelToken.Dispose();
                            CancelToken = new CancellationTokenSource();
                            _savingThread.Start();
                            _running = true;
                            if (Started != null)
                                Started(this, EventArgs.Empty);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// TODO: try to use CancellableToken
        /// </summary>
        void SavingThreadStart()
        {
            while (!CancelToken.Token.IsCancellationRequested)
            {
                if (_messageQueue.Count > 0)
                {
                    var items = _messageQueue.Dequeue(_messageBatchCount);
                    ChatMessage[] messages = items.OfType<ChatMessage>().ToArray();
                    _messageRepo.SaveMessages(messages);
                    _messageRepo.Commit();
                }
                else
                {
                    Thread.Sleep(20);
                }
            }
        }

        /// <summary>
        /// Just add messages to queue to save to DB later
        /// </summary>
        /// <param name="messages"></param>
        /// <param name="fromWebSocketClient"></param>
        public void SaveMessages(ChatMessage[] messages)
        {
            //after that clone them to save to DB
            var list = new List<ChatMessage>();
            foreach (var m in messages)
            {
                list.Add(m.Clone() as ChatMessage);
            }
            _messageQueue.Queue(list.ToArray());
        }
    }
}
